package com.macaline.service.impl;

import cn.hutool.core.date.DateUtil;
import com.google.common.util.concurrent.RateLimiter;
import com.macaline.bean.Result;
import com.macaline.entity.Seckill;
import com.macaline.mapper.BaseMapper;
import com.macaline.mapper.SeckillMapper;
import com.macaline.service.SeckillServie;
import com.macaline.service.base.BaseService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 秒杀
 */
@Service
public class SeckillServiceImpl extends BaseService<Seckill> implements SeckillServie {


    @Resource
    private SeckillMapper seckillMapper;

    @Override
    public BaseMapper<Seckill> getMapper() {
        return seckillMapper;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    Random random = new Random();

    final RateLimiter rateLimiter = RateLimiter.create(1); // 表示每秒产生的令牌数
    /**
     * 库存减一
     * synchronized 可解决超卖问题
     * ReentrantLock 可解决超卖问题，效率慢于synchronized
     * RateLimiter  也可以解决问题
     * @param seckill
     */
    public Result  reduceNum(Seckill seckill) throws InterruptedException {
        lock.lock();

        // 创造三分之一的失败率
        int i1 = random.nextInt(5);
        if(i1 == 1){
            lock.unlock();
            return Result.error("运行过程中出错");
        }

//        boolean b = rateLimiter.tryAcquire(1, TimeUnit.SECONDS);
//        if(!b){
//            System.out.println("限流中断");
//            return Result.error("限流中断");
//        }
        Seckill byId = getById(seckill.getId().toString());
        if(byId.getNum() < 1){
            lock.unlock();
            return Result.error("库存已不足");
        }
        byId.setNum(byId.getNum()- 1);
        Random random = new Random();
        int i = random.nextInt(5);
        TimeUnit.SECONDS.sleep((long) i);
        byId.setUpdateNum(byId.getUpdateNum() + 1);
        seckillMapper.updateById(byId);
        atomicInteger.getAndAdd(1);
        lock.unlock();
        System.out.println("库存：" + byId.getNum() + ":" + DateUtil.formatDateTime(new Date()));
        return Result.success();
    }

    public Result getCount() {
        return Result.success(atomicInteger.get());
    }

    public Result refreshCount() {
        atomicInteger.set(0);
        return Result.success(atomicInteger.get());
    }

    public void update(Seckill s) {
        seckillMapper.updateById(s);
    }
}
